
#include "include/types.h"
#include "include/riscv.h"
#include "include/defs.h"
#include "include/date.h"
#include "include/param.h"
#include "include/memlayout.h"
#include "include/spinlock.h"
#include "include/proc.h"
#include "include/debug.h"

uint64
sys_exit(void)
{
  int n;
  if(argint(0, &n) < 0)
    return -1;
  exit(n);
  return 0;  // not reached
}

uint64
sys_getpid(void)
{
  return myproc()->pid;
}

uint64
sys_getppid(void)
{  
  return myproc()->parent->pid;
}

uint64
sys_getpgid(void)
{
  return 0;
}

uint64
sys_setpgid(void)
{
  return 0;
}

uint64 
sys_gettid(void)
{
  return 0;
}

uint64 
sys_getuid(void)
{
  return 0;
}

uint64 
sys_geteuid(void)
{
  return 0;
}
uint64 
sys_getgid(void)
{
  return 0;
}
uint64 
sys_getegid(void)
{
  return 0;
}
uint64 
sys_set_tid_address(void)
{
  return 0;
}

uint64 sys_sched_yield(void)
{
  yield();
  return 0;
}
uint64 
sys_fork(void)
{
  int flag;
  if (argint(0, &flag) < 0) {
    printf("flag = %d\n", flag);
    return -1;
  }
  printf("flag = %d\n", flag);
  return fork(flag, 0, 0, 0);
}


uint64 
sys_clone(void) 
{
  int flag;
  if (argint(0, &flag) < 0) {
    return -1;
  }
  uint64 stacktop; // 0(stacktop) = func, 8(stacktop) = arg, mention: arg is a pointer to user space
  if (argaddr(1, &stacktop) < 0) {
    return -1;
  }
  uint64 fn = 0;
  uint64 arg = 0;
  if (stacktop > 0) {
    fetchaddr(stacktop, &fn);
    fetchaddr(stacktop + 8, &arg);
    return fork(flag, fn, arg, stacktop);
  }
  else {
    return fork(flag, 0, 0, 0);
  }
}
uint64
sys_wait(void)
{
  // test-user: syscall(SYS_wait4, -1, code, 0); pid默认为-1
  //                                0     1  2                            
  // xv6-user: wait(int*)        也有可能是wait(0)
  //                 0  
  uint64 p;
  if(argaddr(1, &p) < 0)
    return -1;
  return wait(p);
}
uint64 sys_waitpid(void)
{
  // wait.c: waitpid(-1, code, 0); -1 意味着可以等待任何进程
  // waitpid.c: waitpid(cpid, &wstatus, 0); 等待进程ID为cpid的进程，status是接收状态的指针
  // test-user: syscall(SYS_wait4, -1, code, 0); pid默认为-1
  //                                0     1  2                            
  // xv6-user: wait(int*)        也有可能是wait(0)
  //                 0  
  uint64 p;
  int cpid;
  if(argint(0, &cpid) < 0 || argaddr(1, &p) < 0){
    return -1;
  }
  if(cpid == -1){
     // wait any child process
    return wait(p);
  }
  else{
    // wait child process with cpid
    return waitpid(cpid, p);
  }
}
uint64
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  struct proc * p = myproc();
  addr = p->sz; // Size of process memory (bytes)
  if (n > 0) {
    p->sz += n;
  }
  if (n < 0) {
    p->sz = uvmdealloc(p->pagetable, addr, addr + n);
  }
  return addr;
}
uint64
sys_brk(void)
{
  int newsz, oldsz, n;
  if(argint(0, &newsz) < 0)
    return -1;
  struct proc * p = myproc();
  oldsz = p->sz; // Size of process memory (bytes)
  __debug_info("brk", "oldsz = 0x%x\n", oldsz);
  __debug_info("brk", "newsz = 0x%x\n", newsz);
  if(newsz == 0) return oldsz;
  else {
    n = newsz - oldsz;
    uint64 addr;
    addr = p->sz;
    if (n > 0) {
      p->sz += n;
    }
    else {
      p->sz = uvmdealloc(p->pagetable, addr, addr + n);
    }
    return newsz;
  }
}
uint64
sys_sleep(void)
{
  int n;
  uint ticks0;
  if(argint(0, &n) < 0)
    return -1;
  acquire(&tickslock);
  ticks0 = ticks;
  while(ticks - ticks0 < n){
    if(myproc()->killed){
      release(&tickslock);
      return -1;
    }
    sleep(&ticks, &tickslock);
  }
  release(&tickslock);
  return 0;
}

uint64
sys_nanosleep(void)
{
  uint64 addr;
  uint ticks0;
  // test-user:     
  //          TimeVal tv = {.sec = time, .usec = 0}; 秒数+微妙数
  //          syscall(SYS_nanosleep, &tv, &tv) return tv.sec;
  //                                  0    1
  // xv6-user: sleep(10); one second
  //                 0
  if(argaddr(0, &addr) < 0)
    return -1;
  uint64 sec;
  struct proc * p = myproc();
  copyin(p->pagetable, (char *)&sec, addr, sizeof(sec));
  acquire(&tickslock);
  ticks0 = ticks;
  while(ticks - ticks0 < sec){
    if(myproc()->killed){
      release(&tickslock);
      return -1;
    }
    sleep(&ticks, &tickslock);
  }
  release(&tickslock);
  return 0;
}
uint64
sys_kill(void)
{
  int pid;

  if(argint(0, &pid) < 0)
    return -1;
  return kill(pid);
}

// return how many clock tick interrupts have occurred
// since start.
uint64
sys_uptime(void)
{
  uint xticks;

  acquire(&tickslock);
  xticks = ticks;
  release(&tickslock);
  return xticks;
}

uint64
sys_trace(void)
{
  int mask;
  if(argint(0, &mask) < 0) {
    return -1;
  }
  myproc()->tmask = mask;
  return 0;
}

uint64 sys_rt_sigprocmask(void)
{
  return 0;
}
uint64 sys_rt_sigaction(void)
{
  return 0;
}